package com.fingard.dsp.bank.directbank.yeepay01;

import com.cfca.util.pki.api.SignatureUtil;
import com.cfca.util.pki.cipher.JCrypto;
import com.fingard.crypto.SignVerifyHelper;
import com.fingard.dsp.bank.directConfig.ActSetItem;
import com.fingard.dsp.bank.directbank.FailCode;
import com.fingard.dsp.bank.directbank.PaymentState;
import com.fingard.dsp.bank.directbank.bankInterface.ISinglePay;
import com.fingard.dsp.bank.reqrespobj.single.*;
import com.fingard.dsp.bank.reqrespobj.single.detail.RetAtsSglDetail;
import com.fingard.io.FileHelper;
import com.fingard.util.CallbackUtils;
import com.fingard.util.Digest;
import com.fingard.xml.XmlTextReader;
import com.fingard.xml.XmlTextWriter;

public class YEEPAY01SinglePay extends YEEPAY01Base implements ISinglePay {

	public RetAtsSingle d_1908_SglPay(ReqSingle p_req1908) throws Exception {
		RetAtsSingle retAts = new RetAtsSingle(p_req1908.reqHeader);
		RetAtsSglDetail tmpRetDetail;
		tmpRetDetail = d_190801(p_req1908);
		retAts.writeRetDetail(tmpRetDetail);
		return retAts;
	}

	@Override
	public RetAtsSingleBat d_1908BAT_SglBatPay(ReqSingleBat p_req1908BAT) throws Exception {
		return null;
	}

	private RetAtsSglDetail d_190801(ReqSingle p_req1908) throws Exception {
		RetAtsSglDetail retDetail = new RetAtsSglDetail();
		YEEPAY01Header header = new YEEPAY01Header();
		// 取第三方商户
		ActSetItem actItem = getBankConfig().getActSetItem(p_req1908.singleDetail.payAct, "");
		if (actItem == null || !FileHelper.existFile(actItem.ownKeyStorePath)) {
			retDetail.respCode = "-1";
			if (actItem == null) {
				retDetail.respInfo = "未找到账号" + p_req1908.singleDetail.payAct + "的批量商户配置节点";
			} else {
				retDetail.respInfo = "账号" + p_req1908.singleDetail.payAct + "的证书文件不存在";
			}
			retDetail.reqSeqID = p_req1908.singleDetail.askNumber;
			retDetail.transState = PaymentState.FAIL_Batch;
			retDetail.payInfoCode = FailCode.E9981;
			return retDetail;
		}
		header.cmd = "TransferSingle";
		header.mer_Id = actItem.merchantId;
		header.group_Id = actItem.termId;
		header.product = "RJT";
		XmlTextWriter xmlWriter = new XmlTextWriter();
		writeCommonHeader(xmlWriter, header);
		xmlWriter.writeElementString("batch_No", p_req1908.singleDetail.askNumber);
		String order_Id = p_req1908.singleDetail.askNumber;
		xmlWriter.writeElementString("order_Id", order_Id+"7");
		String bankCode = getBankConfig().getMapValueByKey("bankMapping", p_req1908.singleDetail.recBankCode);
		xmlWriter.writeElementString("bank_Code", bankCode); //  收款银行编号 否
		xmlWriter.writeElementString("cnaps", p_req1908.singleDetail.cnapsCode);// 联行号 否 
		xmlWriter.writeElementString("bank_Name", p_req1908.singleDetail.payBankName); //收款银行全称 否 
		xmlWriter.writeElementString("branch_Bank_Name", p_req1908.singleDetail.recBankLocation);//收款银行支行名称		否 
		xmlWriter.writeElementString("amount", p_req1908.singleDetail.payAmount);
		xmlWriter.writeElementString("account_Name", p_req1908.singleDetail.recName);
		xmlWriter.writeElementString("account_Number", p_req1908.singleDetail.recAct);
		String accountType = p_req1908.singleDetail.isPrivate.equals("1") ? "pr" : "pu";//账户类型 否 对公：pu;对私：pr;不填写默认		对私
		xmlWriter.writeElementString("account_Type", accountType);
//		String province = getBankConfig().getMapValueByKey("cityMapping", p_req1908.singleDetail.recArea)+"00";
//		String city = p_req1908.singleDetail.recArea+"00";
		xmlWriter.writeElementString("province", "");//收款行省份		编码		否 
		xmlWriter.writeElementString("city", "");//收款行市		编码		否 
		xmlWriter.writeElementString("fee_Type", getBankConfig().getValueAsString("feeType"));
		String urgency = p_req1908.singleDetail.paySpd.equals("0") ? "0" : "1";
		xmlWriter.writeElementString("payee_Email", "");
		xmlWriter.writeElementString("payee_Mobile", "");
		xmlWriter.writeElementString("leave_Word", "");
		xmlWriter.writeElementString("abstractInfo", "");
		xmlWriter.writeElementString("remarksInfo", p_req1908.singleDetail.memo);
		xmlWriter.writeElementString("urgency", urgency);
		System.out.println("=================" + xmlWriter.toXmlString());
		// 签名
		String hmacStr = header.cmd + header.mer_Id + p_req1908.singleDetail.askNumber + order_Id + p_req1908.singleDetail.payAmount
				+ p_req1908.singleDetail.recAct + actItem.saltKey;

		SignVerifyHelper signVerifyHelper = new SignVerifyHelper();
		String hmac = signVerifyHelper.buildCertSign(hmacStr, actItem.ownKeyStorePath, actItem.ownKeyPassword);
		xmlWriter.writeElementString("hmac", hmac);
		xmlWriter.writeEndElement();
		xmlWriter.writeEndDocument();// 写入报文完成
		String reqStr = new String(xmlWriter.toXmlString().getBytes(), "GBK");
		// 第四步:发送https请求
		String responseMsg = CallbackUtils.httpRequest(bankFront.serverURL, reqStr, "POST", "gbk", "text/xml ;charset=gbk", false);
		System.out.println("服务器响应xml报文:" + responseMsg);
//		Document document = null;
//		Element rootEle = null;
		SignatureUtil signUtil = new SignatureUtil();
//		Map xmlBackMap = new LinkedHashMap();
		JCrypto jcrypto = null;
		com.cfca.util.pki.cipher.Session tempsession = null;
		if (tempsession == null) {
			try {
				// 初始化加密库，获得会话session
				// 多线程的应用可以共享一个session,不需要重复,只需初始化一次
				// 初始化加密库并获得session。
				// 系统退出后要jcrypto.finalize()，释放加密库
				jcrypto = JCrypto.getInstance();
				jcrypto.initialize(JCrypto.JSOFT_LIB, null);
				tempsession = jcrypto.openSession(JCrypto.JSOFT_LIB);
			} catch (Exception ex) {
				System.out.println(ex.toString());
			}
		}
//		// 第五步:对服务器响应报文进行验证签名
		boolean sigerCertFlag = false;
		if (!responseMsg.isEmpty()) {
			StringBuilder tmpSbMsg = new StringBuilder();
			XmlTextReader tmpBkReader = loadBankRespXmlReader(responseMsg, tmpSbMsg);
			if (tmpBkReader != null) {
				String cmd = tmpBkReader.getFirstText("/data/cmd"); // 参与签名
				String retCode = tmpBkReader.getFirstText("/data/ret_Code"); // 参与签名
				String tranStt = tmpBkReader.getFirstText("/data/r1_Code"); // 参与签名
				order_Id = tmpBkReader.getFirstText("/data/order_Id");
				String bankStatus = tmpBkReader.getFirstText("/data/bank_Status");
				String errorMsg = tmpBkReader.getFirstText("/data/error_Msg");
				String result = PaymentState.FAIL;;
				hmac = tmpBkReader.getFirstText("/data/hmac");
				if (hmac != null) {
					sigerCertFlag = signUtil.p7VerifySignMessage(hmac.getBytes(), tempsession);
					String backmd5hmac = hmac;
					if (sigerCertFlag) {
						WriteBankLogLn2("证书验签成功");
						backmd5hmac = new String(signUtil.getSignedContent());
						WriteBankLogLn2("证书验签获得的MD5签名数据为----" + backmd5hmac);
						WriteBankLogLn2("证书验签获得的证书dn为----" + new String(signUtil.getSigerCert()[0].getSubject()));
						// 第六步.将验签出来的结果数据与自己针对响应数据做MD5签名之后的数据进行比较是否相等
						String backHmacStr = ((cmd == null) ? "" : cmd) + ((retCode == null) ? "" : retCode) + ((tranStt == null) ? "" : tranStt)
								+ ((actItem.saltKey == null) ? "" : actItem.saltKey);
						String newmd5hmac = Digest.hmacSign(backHmacStr);
						WriteBankLogLn2("提交返回源数据为---||" + backHmacStr + "||");
						WriteBankLogLn2("经过md5签名后的验证返回hmac为---||" + newmd5hmac + "||");
						WriteBankLogLn2("提交返回的hmac为---||" + backmd5hmac + "||");
						if (newmd5hmac.equals(backmd5hmac)) {
							WriteBankLogLn2("md5验签成功");
							// 第七步:判断该证书DN是否为易宝
							if (signUtil.getSigerCert()[0].getSubject().toUpperCase().indexOf("OU=YEEPAY,") > 0) {
								WriteBankLogLn2("证书DN是易宝的");
								// 第八步:.......加上业务逻辑
								result = judgeResult(retCode, tranStt, bankStatus);
							} else {
								WriteBankLogLn2("证书DN不是易宝的");
							}
						} else {
							WriteBankLogLn2("md5验签失败");
							retDetail.respCode = "-1";
							retDetail.payInfoCode="0";
							retDetail.transState = result;
							return retDetail;
						}
					} else {
						WriteBankLogLn2("证书验签失败....");
						retDetail.respCode = "-1";
						retDetail.payInfoCode="0";
						retDetail.transState = result;
						return retDetail;
					}
				}
				retDetail.respCode = "0";
				retDetail.respInfo = errorMsg;
				retDetail.reqSeqID = p_req1908.singleDetail.askNumber;
				retDetail.transState = result;
				retDetail.payInfoCode = tmpBkReader.getFirstText("/data/r1_Code");
				
			} else {
				retDetail.respCode = "-1";
				retDetail.respInfo = tmpSbMsg.toString();
			}
		} else {
			retDetail.respCode = "-1";
		}
		return retDetail;
	}

	// 1944 状态查询
	public RetAtsSingle d_1944_QrySglPay(ReqQrySingle p_req1944) throws Exception {
		// 返回ATS的对象
		RetAtsSingle retAts = new RetAtsSingle(p_req1944.reqHeader);
		RetAtsSglDetail tmpRetAtsDetail = new RetAtsSglDetail();
		YEEPAY01Header header = new YEEPAY01Header();
		XmlTextWriter xmlWriter = new XmlTextWriter();
		header.cmd = "BatchDetailQuery";
		header.version = "1.0";
		// 取第三方商户
		ActSetItem actItem = getBankConfig().getActSetItem(p_req1944.payAct, "");
		if (actItem == null || !FileHelper.existFile(actItem.ownKeyStorePath)) {
			tmpRetAtsDetail.respCode = "0";
			if (actItem == null) {
				tmpRetAtsDetail.respInfo = "未找到账号" + p_req1944.payAct + "的批量商户配置节点";
			} else {
				tmpRetAtsDetail.respInfo = "账号" + p_req1944.payAct + "的证书文件不存在";
			}
			tmpRetAtsDetail.reqSeqID = p_req1944.askNumber;
			tmpRetAtsDetail.transState = PaymentState.FAIL_Batch;
			tmpRetAtsDetail.payInfoCode = FailCode.E9981;
			retAts.writeRetDetail(tmpRetAtsDetail);
			return retAts;
		}
		header.group_Id = actItem.termId;
		header.mer_Id = actItem.merchantId;
		header.product="RJT";
		writeCommonHeader(xmlWriter, header);
		xmlWriter.writeElementString("query_Mode", "3");
		xmlWriter.writeElementString("batch_No", p_req1944.askNumber);
		xmlWriter.writeElementString("order_Id", p_req1944.askNumber);
		xmlWriter.writeElementString("page_No", "1"); // 单笔穿1
		// 签名  cmd 、 mer_Id 、 batch_No 、order_Id 、page_No 的参数值+商户密钥组成字符串
		String hmacStr = header.cmd + header.mer_Id + p_req1944.askNumber + p_req1944.askNumber + "1" + actItem.saltKey;
		SignVerifyHelper signVerifyHelper = new SignVerifyHelper();
		String hmac = signVerifyHelper.buildCertSign(hmacStr, actItem.ownKeyStorePath, actItem.ownKeyPassword);
		xmlWriter.writeElementString("hmac", hmac);
		xmlWriter.writeEndDocument();
		try {
			String reqStr = new String(xmlWriter.toXmlString().getBytes(), "GBK");
			// 第四步:发送https请求
			String responseMsg = CallbackUtils.httpRequest(bankFront.serverURL, reqStr, "POST", "gbk", "text/xml ;charset=gbk", false);
			System.out.println(responseMsg);
			StringBuilder tmpSbMsg = new StringBuilder();
			XmlTextReader tmpBkReader = loadBankRespXmlReader(responseMsg, tmpSbMsg);
			if (!responseMsg.isEmpty()) {
				String retCode = tmpBkReader.getFirstText("/data/ret_Code");
				String tranStt = tmpBkReader.getFirstText("/data/list/items/item/r1_Code");
				String bankStatus = tmpBkReader.getFirstText("/data/list/items/item/bank_Status ");
				String amount = tmpBkReader.getFirstText("/data/list/items/item/amount");
				tmpRetAtsDetail.respInfo = tmpBkReader.getFirstText("/data/error_Msg");
				tmpRetAtsDetail.reqSeqID = p_req1944.askNumber;
				String result = judgeResult(retCode, tranStt, bankStatus);
				tmpRetAtsDetail.respCode = "0";
				tmpRetAtsDetail.transState = result;
//				tmpRetAtsDetail.respInfo = responseMsg;
				tmpRetAtsDetail.transAmt = amount;
			} else {
				tmpRetAtsDetail.respCode = "-1";
				tmpRetAtsDetail.respInfo = responseMsg;
			}
		} catch (Exception e) {
			tmpRetAtsDetail.respCode = "-1";
			tmpRetAtsDetail.respInfo = e.getMessage();
			e.printStackTrace();
		}
		retAts.writeRetDetail(tmpRetAtsDetail);
		return retAts;
	}

	@Override
	public RetAtsSingleBat d_1944BAT_QrySglBatPay(ReqQrySingleBat p_req1944BAT) throws Exception {
		return null;
	}

	/**
	 * 
	 * @param retCode
	 * @param tranStt
	 * @param bankStatus
	 * @return
	 */
	private String judgeResult(String retCode, String tranStt, String bankStatus) {
		if ("1".equals(retCode)) {
			if ("0030".equals(tranStt)) {
				return PaymentState.EXCEPTION;
			} else if ("0029".equals(tranStt)) {
				return PaymentState.PAYING;
			} else if ("0028".equals(tranStt)) {
				return PaymentState.FAIL;
			} else if ("0027".equals(tranStt)) {
				return PaymentState.FAIL;
			} else if ("0026".equals(tranStt)) {
				if ("S".equals(bankStatus)) {
					return PaymentState.SUCCESS;
				} else {
					return PaymentState.PAYING;
				}
			} else {//"0025"
				return PaymentState.PAYING;
			}
		} else if ("9999".equals(retCode)) {
			return PaymentState.EXCEPTION;
		} else{
			return PaymentState.FAIL;
		}
	}
}
